library(Seurat)
library(ggplot2)
library(pheatmap)
library(tidyverse)
── Attaching packages ──────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ tibble  3.1.3     ✓ stringr 1.4.0
✓ readr   2.0.1     ✓ forcats 0.5.1
✓ purrr   0.3.4     
── Conflicts ─────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
fig_dir = file.path("figs","brain_plot")
dir.create(fig_dir)
Warning in dir.create(fig_dir) : 'figs/brain_plot' already exists
srt95 = saveRDS(file = "data/srt_E95.Rds")
Error in saveRDS(file = "data/srt_E95.Rds") : 
  argument "object" is missing, with no default
srt33 = srt95[,srt95$orig.ident=="201104_33"]
library(dbscan)


db_out = dbscan(srt33@reductions$spatial@cell.embeddings,60)

ggplot(data=NULL,aes(x=srt33@reductions$spatial@cell.embeddings[,1],y=srt33@reductions$spatial@cell.embeddings[,2],col= factor(db_out$cluster)))+
         geom_point(size=0.8)+
  coord_fixed()+
  theme_classic()


sel_clu = names(table(db_out$cluster)[order(table(db_out$cluster),decreasing = T)][1])
sel_clu
[1] "1"
srt33 = srt33[,db_out$cluster==sel_clu]

saveRDS(srt33,file="data/srt33_clean.Rds")
sel_cluster = 23
DimPlot(srt33,reduction = "spatial",cells.highlight=colnames(srt33)[srt33$seurat_clusters==sel_cluster])+ggtitle(paste0("cluster ",sel_cluster))+coord_fixed()

srt_sel = srt33[,srt33$seurat_clusters==sel_cluster]

db_out = dbscan(srt_sel@reductions$spatial@cell.embeddings,60)

ggplot(data=NULL,aes(x=srt_sel@reductions$spatial@cell.embeddings[,1],y=srt_sel@reductions$spatial@cell.embeddings[,2],col= factor(db_out$cluster)))+
         geom_point(size=0.8)+
  coord_fixed()+
  theme_classic()


sel_clu = names(table(db_out$cluster)[order(table(db_out$cluster),decreasing = T)][1])
sel_clu
[1] "1"
srt_sel = srt_sel[,db_out$cluster==sel_clu]
library(edgeR)
Loading required package: limma
library(limma)

cnts = srt_sel@assays$RNA@counts
cnts = cnts[rowSums(cnts)>20,]
cnts = as.matrix(cnts)
allcounts = DGEList(counts=cnts)
allcounts = estimateDisp(allcounts, robust=TRUE)
Using classic mode.
  design_mat = model.matrix(~ srt_sel@reductions$spatial@cell.embeddings[,2])
  fit = glmQLFit(allcounts, design_mat)
  lrt = glmQLFTest(fit)
  top = topTags(lrt,n=Inf)
  top
Coefficient:  srt_sel@reductions$spatial@cell.embeddings[, 2] 
srt_markers = srt_sel@misc$markers
top10 <- srt_markers[srt_markers$p_val_adj<0.01,] #%>% group_by(cluster) %>% top_n(n = 30, wt = -p_val_adj) # %>%  top_n(n = 5, wt = avg_logFC)
top10$pct_diff = top10$pct.1-top10$pct.2
top10 = top10[top10$pct_diff>0.1,]
top10 = top10 %>% group_by(gene) %>% top_n(n=1,wt=avg_log2FC)

top10 = top10[top10$cluster %in% sel_cluster,]
top_sel = top$table[rownames(top$table) %in% top10$gene,]
top_sel = top_sel[top_sel$FDR<0.05,]
write.csv(top_sel,file =file.path(fig_dir, paste0("DE_markersforcluster_",sel_cluster,".csv")))
top_sel
sel_gene = c("Tcf7l2","Nr2f2","Wfdc1","Tal2","Boc","Zic4")
FeaturePlot(srt_sel,features = sel_gene,reduction = "spatial",coord.fixed = T,order=T,pt.size=0.5,ncol=3)
ggsave(file.path(fig_dir,paste0("markergene_",sel_cluster,"_region.pdf")))
Saving 7.29 x 4.5 in image

FeaturePlot(srt33,features = sel_gene,reduction = "spatial",coord.fixed = T,order=T,ncol=3,pt.size=0.01)

ggsave(file.path(fig_dir,paste0("markergene_",sel_cluster,"_allpuck.pdf")))
Saving 9 x 4 in image
sel_clusters = c(23, 27)
srt_sel = srt33[,srt33$seurat_clusters %in% sel_clusters]

db_out = dbscan(srt_sel@reductions$spatial@cell.embeddings,60)

ggplot(data=NULL,aes(x=srt_sel@reductions$spatial@cell.embeddings[,1],y=srt_sel@reductions$spatial@cell.embeddings[,2],col= factor(db_out$cluster)))+
         geom_point(size=0.8)+
  coord_fixed()+
  theme_classic()


sel_clu = names(table(db_out$cluster)[order(table(db_out$cluster),decreasing = T)][1])

srt_sel = srt_sel[,db_out$cluster==sel_clu]


cnts = srt_sel@assays$RNA@counts
cnts = cnts[rowSums(cnts)>20,]
cnts = as.matrix(cnts)
allcounts = DGEList(counts=cnts)
allcounts = estimateDisp(allcounts, robust=TRUE)
Using classic mode.
  design_mat = model.matrix(~ srt_sel@reductions$spatial@cell.embeddings[,2])
  fit = glmQLFit(allcounts, design_mat)
  lrt = glmQLFTest(fit)
  top = topTags(lrt,n=Inf)


srt_markers = srt_sel@misc$markers
top10 <- srt_markers[srt_markers$p_val_adj<0.01,] #%>% group_by(cluster) %>% top_n(n = 30, wt = -p_val_adj) # %>%  top_n(n = 5, wt = avg_logFC)
top10$pct_diff = top10$pct.1-top10$pct.2
top10 = top10[top10$pct_diff>0.2,]
#top10 = top10 %>% group_by(gene) %>% top_n(n=1,wt=avg_log2FC)

top10 = top10[top10$cluster %in% sel_clusters,]

top_sel = top$table[rownames(top$table) %in% top10$gene,]
top_sel = top_sel[top_sel$FDR<0.05,]
write.csv(top_sel,file =file.path(fig_dir, paste0("DE_markersforcluster_23_27.csv")))
top_sel
sel_gene = c("Tcf7l2","Dmrta2","Rprm","Tubb3","Pcdh8","Shh")
FeaturePlot(srt_sel,features = sel_gene,reduction = "spatial",coord.fixed = T,order=T,pt.size=0.5,ncol=3)
ggsave(file.path(fig_dir,paste0("markergene_23_27_region.pdf")))
Saving 7.29 x 4.5 in image

FeaturePlot(srt33,features = sel_gene,reduction = "spatial",coord.fixed = T,order=T,ncol=3,pt.size=0.01)

ggsave(file.path(fig_dir,paste0("markergene_23_27_allpuck.pdf")))
Saving 9 x 4 in image

srt_sel$MHB = "no"
srt_sel$MHB[srt_sel$ycoord>2900 & srt_sel$ycoord < 3180 & srt_sel$xcoord>4900] = "yes"

DimPlot(srt_sel,reduction = "spatial",group.by = "MHB")+coord_fixed()

sel_gene = rownames(markers.MHB[markers.MHB$p_val_adj<0.05,])
FeaturePlot(srt_sel,features = sel_gene,reduction = "spatial",coord.fixed = T,order=T,pt.size=0.3,ncol=4)

ggsave(file.path(fig_dir,paste0("markergene_23_27_MHB.pdf")))
Saving 10 x 8 in image

eye genes

eye_genes = c("Rax", "Vax1", "Vax2", "Pax2", "Six6")
FeaturePlot(srt33,features = eye_genes,reduction = "spatial",coord.fixed = T,order=T,ncol=3,pt.size=0.01)

srt33_eye = ScaleData(srt33,features = unique(c(VariableFeatures(srt33), eye_genes)) ,verbose=F)
expand_genes = c()
for(ge in c("Rax","Vax1","Six6")){
  print(ge)
  corr = t(cor((srt33_eye@assays$RNA@scale.data[ge,]), t(srt33_eye@assays$RNA@scale.data )))[,1]
  corr = corr[!is.na(corr)]
  corr = corr[order(corr,decreasing = T)]
  expand_genes = c(expand_genes, names(head(corr))[2:6])
}
[1] "Rax"
Warning in cor((srt33_eye@assays$RNA@scale.data[ge, ]), t(srt33_eye@assays$RNA@scale.data)) :
  the standard deviation is zero
[1] "Vax1"
Warning in cor((srt33_eye@assays$RNA@scale.data[ge, ]), t(srt33_eye@assays$RNA@scale.data)) :
  the standard deviation is zero
[1] "Six6"
Warning in cor((srt33_eye@assays$RNA@scale.data[ge, ]), t(srt33_eye@assays$RNA@scale.data)) :
  the standard deviation is zero
srt33_eye = FindNeighbors(srt33_eye,dims = 1:5,verbose=F)

sel_spa = srt33_eye@reductions$spatial@cell.embeddings[srt33_eye$seurat_clusters==1,]
plot(sel_spa)

db_out = dbscan(sel_spa,eps=50)

ggplot(data=NULL,aes(x=sel_spa[,1],y=sel_spa[,2],col=as.factor(db_out$cluster)))+
  geom_point()

idx = rownames(sel_spa)[db_out$cluster==1]
srt33_eye$eye = "no"
srt33_eye$eye[colnames(srt33_eye) %in% idx] = "yes"
paste(sum(srt33_eye$eye=="yes"),"/",ncol(srt33_eye[,srt33_eye$RNA_snn_res.1 %in% c(0,1,15,21,23,27)]),"=",sum(srt33_eye$eye=="yes")/ncol(srt33_eye[,srt33_eye$RNA_snn_res.1 %in% c(0,1,15,21,23,27)]))
[1] "105 / 4824 = 0.0217661691542289"
paste(sum(srt33_eye$eye=="yes"),"/",sum(srt33_eye$RNA_snn_res.1==0),"=", sum(srt33_eye$eye=="yes")/sum(srt33_eye$RNA_snn_res.1==0))
[1] "105 / 1499 = 0.0700466977985324"
paste(sum(srt33_eye$RNA_snn_res.1==0),"/",ncol(srt33_eye),"=", sum(srt33_eye$RNA_snn_res.1==0)/ncol(srt33_eye))
[1] "1499 / 18260 = 0.082092004381161"
save.csv(marker.eye[marker.eye$p_val_adj<0.01 & marker.eye$avg_log2FC>0,],file="data/eyes_marker.csv")
Error in save.csv(marker.eye[marker.eye$p_val_adj < 0.01 & marker.eye$avg_log2FC >  : 
  could not find function "save.csv"

expand_genes_eye = c()
for(ge in c("Cp","Vwc2")){
  print(ge)
  corr = t(cor((srt33_eye_sel@assays$RNA@scale.data[ge,]), t(srt33_eye_sel@assays$RNA@scale.data )))[,1]
  corr = corr[!is.na(corr)]
  corr = corr[order(corr,decreasing = T)]
  expand_genes_eye = c(expand_genes_eye, names(head(corr,n=10))[2:10])
}
[1] "Cp"
[1] "Vwc2"

DimPlot(srt33_eye_sel,reduction = "spatial",pt.size = 4)+coord_fixed()
ggsave(file.path(fig_dir,"eye_subset_clustering.pdf"))
Saving 7.29 x 4.5 in image


DotPlot(srt33_eye_sel,features = unique(c(unique(top10$gene),"Cp","Vwc2")),cols="Spectral")+coord_flip()
ggsave(file.path(fig_dir,"eye_subset_markers_dotplot.pdf"))
Saving 7.29 x 4.5 in image

FeaturePlot(srt33_eye_sel,features = c("Vwc2","Jkamp","Cp","Tlk1","Pon2","Ict1"),coord.fixed = T,sort.cell = T,reduction = "spatial",ncol = 3)
Warning: The sort.cell parameter is being deprecated. Please use the order parameter instead for equivalent functionality.
ggsave(file.path(fig_dir,"eye_subset_markers_spatial.pdf"))
Saving 7.29 x 4.5 in image

pp = FeaturePlot(srt33_eye,features = rownames(marker.eye)[1:12],order = T,raster = F,ncol = 4,coord.fixed = T,reduction = "spatial",max.cutoff = "q99")
ggsave(file.path(fig_dir,paste0("spatial_eye_markers.pdf")),plot = pp,width = 14,height = 9)
srt36 = srt95[,srt95$orig.ident=="201104_36"]
pp = FeaturePlot(srt36,features = rownames(marker.eye)[1:12],order = T,raster = F,ncol = 4,coord.fixed = T,reduction = "spatial",max.cutoff = "q99")
ggsave(file.path(fig_dir,paste0("spatial_eye_markers_36.pdf")),plot = pp,width = 14,height = 9)
load("~/scRNAseq_reference_datasets/WT.Robj")

FeaturePlot(WT,features = c("Six6","Cp","Vwc2"),order=T,split.by = "stage")
Warning in FeaturePlot(WT, features = c("Six6", "Cp", "Vwc2"), order = T,  :
  All cells have the same value (0) of Six6.
Warning in FeaturePlot(WT, features = c("Six6", "Cp", "Vwc2"), order = T,  :
  All cells have the same value (0) of Cp.
Warning in FeaturePlot(WT, features = c("Six6", "Cp", "Vwc2"), order = T,  :
  All cells have the same value (0) of Vwc2.

WT$eye_cluster = WT@assays$RNA@data["Six6",]>0.7
table(WT$eye_cluster)

FALSE  TRUE 
88322   457 

sparse.cor2

table(WT$eye_cluster,WT$stage)
       
        WT_65 WT_70 WT_75 WT_80 WT_85
  FALSE  2280 13218 27417 23298 22109
  TRUE      0     0     5    46   406
table(WT$eye_cluster,WT$cluster)
       
           0    1   10   11   12   13   14   15   16   17   18   19    2   20   21   22   23   24   25   26   27   28   29    3   30   31   32   33   34   35   36   37   38   39    4   40
  FALSE 3860 4211 3638 2578 2753 2077  862 1907  956  787 2255 5096 2908 2386  887 3041  298 3708 1064 2857  290  530 2650 2322 1819 1594 1158 1297 1555 1972 1606 3137  338 2575 1081 1434
  TRUE     0   85  168    1    2    0    0    0    1    0    0    0    0    0    0    0    0  175    0    1    0    0    0    0    0    1    0    0    2   16    1    0    1    1    0    0
       
          41    5    6    7    8    9
  FALSE  482 3635 2509 1311 4808 2090
  TRUE     0    0    1    0    0    1
WT$eye_clu_fine = "no"
WT$eye_clu_fine[ WT$cluster==10]="clu10"
WT$eye_clu_fine[WT$eye_cluster & WT$cluster==10]="eye_10"
WT$eye_clu_fine[ WT$cluster==24]="clu24"
WT$eye_clu_fine[WT$eye_cluster & WT$cluster==24]="eye_24"
table(WT$eye_clu_fine)

 clu10  clu24 eye_10 eye_24     no 
  3638   3708    168    175  81090 
markers_24 = FindMarkers(WT,ident.1 = "24",group.by = "cluster",only.pos = T,min.diff.pct = 0.1,verbose = F)
eye.24_ref = FindMarkers(WT,ident.1 = "eye_24",ident.2 = "clu24",group.by = "eye_clu_fine",min.diff.pct = 0.1,verbose = F)
eye.24_ref = eye.24_ref[eye.24_ref$p_val_adj<0.01,]
eye.24_ref = eye.24_ref[eye.24_ref$pct.1>0.3 & eye.24_ref$pct.2<0.1,]
eye.24_ref

srt85 = readRDS(file = "data/srt_E85.Rds")
FeaturePlot(srt85,features = c("Six6","Aldh1a3","Foxg1","Cp","Vwc2"),split.by = "orig.ident",ncol=4,reduction = "spatial",coord.fixed = T,order=T)
Warning in FeaturePlot(srt85, features = c("Six6", "Aldh1a3", "Foxg1", "Cp",  :
  All cells have the same value (0) of Six6.
Warning in FeaturePlot(srt85, features = c("Six6", "Aldh1a3", "Foxg1", "Cp",  :
  All cells have the same value (0) of Six6.
Warning in FeaturePlot(srt85, features = c("Six6", "Aldh1a3", "Foxg1", "Cp",  :
  All cells have the same value (0) of Aldh1a3.

ggsave(file.path(fig_dir,"eye_markers_E85.pdf"))
Saving 46 x 10 in image
LS0tCnRpdGxlOiAiRTk1IGJyYWluIGFuYWx5c2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7cn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwaGVhdG1hcCkKbGlicmFyeSh0aWR5dmVyc2UpCmZpZ19kaXIgPSBmaWxlLnBhdGgoImZpZ3MiLCJicmFpbl9wbG90IikKZGlyLmNyZWF0ZShmaWdfZGlyKQpgYGAKCmBgYHtyfQpzcnQ5NSA9IHJlYWRSRFMoZmlsZSA9ICJkYXRhL3NydF9FOTUuUmRzIikKYGBgCgpgYGB7cn0Kc3J0MzMgPSBzcnQ5NVssc3J0OTUkb3JpZy5pZGVudD09IjIwMTEwNF8zMyJdCmBgYAoKYGBge3J9CmxpYnJhcnkoZGJzY2FuKQoKCmRiX291dCA9IGRic2NhbihzcnQzM0ByZWR1Y3Rpb25zJHNwYXRpYWxAY2VsbC5lbWJlZGRpbmdzLDYwKQoKZ2dwbG90KGRhdGE9TlVMTCxhZXMoeD1zcnQzM0ByZWR1Y3Rpb25zJHNwYXRpYWxAY2VsbC5lbWJlZGRpbmdzWywxXSx5PXNydDMzQHJlZHVjdGlvbnMkc3BhdGlhbEBjZWxsLmVtYmVkZGluZ3NbLDJdLGNvbD0gZmFjdG9yKGRiX291dCRjbHVzdGVyKSkpKwogICAgICAgICBnZW9tX3BvaW50KHNpemU9MC44KSsKICBjb29yZF9maXhlZCgpKwogIHRoZW1lX2NsYXNzaWMoKQoKc2VsX2NsdSA9IG5hbWVzKHRhYmxlKGRiX291dCRjbHVzdGVyKVtvcmRlcih0YWJsZShkYl9vdXQkY2x1c3RlciksZGVjcmVhc2luZyA9IFQpXVsxXSkKc2VsX2NsdQpzcnQzMyA9IHNydDMzWyxkYl9vdXQkY2x1c3Rlcj09c2VsX2NsdV0KYGBgCgoKYGBge3J9CkRpbVBsb3Qoc3J0MzMscmVkdWN0aW9uID0gInNwYXRpYWwiKStjb29yZF9maXhlZCgpCmBgYAoKCmBgYHtyfQpzYXZlUkRTKHNydDMzLGZpbGU9ImRhdGEvc3J0MzNfY2xlYW4uUmRzIikKYGBgCgoKCmBgYHtyfQpzZWxfY2x1c3RlciA9IDIzCmBgYAoKCmBgYHtyfQpEaW1QbG90KHNydDMzLHJlZHVjdGlvbiA9ICJzcGF0aWFsIixjZWxscy5oaWdobGlnaHQ9Y29sbmFtZXMoc3J0MzMpW3NydDMzJHNldXJhdF9jbHVzdGVycz09c2VsX2NsdXN0ZXJdKStnZ3RpdGxlKHBhc3RlMCgiY2x1c3RlciAiLHNlbF9jbHVzdGVyKSkrY29vcmRfZml4ZWQoKQpgYGAKCmBgYHtyfQpzcnRfc2VsID0gc3J0MzNbLHNydDMzJHNldXJhdF9jbHVzdGVycz09c2VsX2NsdXN0ZXJdCgpkYl9vdXQgPSBkYnNjYW4oc3J0X3NlbEByZWR1Y3Rpb25zJHNwYXRpYWxAY2VsbC5lbWJlZGRpbmdzLDYwKQoKZ2dwbG90KGRhdGE9TlVMTCxhZXMoeD1zcnRfc2VsQHJlZHVjdGlvbnMkc3BhdGlhbEBjZWxsLmVtYmVkZGluZ3NbLDFdLHk9c3J0X3NlbEByZWR1Y3Rpb25zJHNwYXRpYWxAY2VsbC5lbWJlZGRpbmdzWywyXSxjb2w9IGZhY3RvcihkYl9vdXQkY2x1c3RlcikpKSsKICAgICAgICAgZ2VvbV9wb2ludChzaXplPTAuOCkrCiAgY29vcmRfZml4ZWQoKSsKICB0aGVtZV9jbGFzc2ljKCkKCnNlbF9jbHUgPSBuYW1lcyh0YWJsZShkYl9vdXQkY2x1c3Rlcilbb3JkZXIodGFibGUoZGJfb3V0JGNsdXN0ZXIpLGRlY3JlYXNpbmcgPSBUKV1bMV0pCnNlbF9jbHUKc3J0X3NlbCA9IHNydF9zZWxbLGRiX291dCRjbHVzdGVyPT1zZWxfY2x1XQpgYGAKCgpgYGB7cn0KbGlicmFyeShlZGdlUikKbGlicmFyeShsaW1tYSkKCmNudHMgPSBzcnRfc2VsQGFzc2F5cyRSTkFAY291bnRzCmNudHMgPSBjbnRzW3Jvd1N1bXMoY250cyk+MjAsXQpjbnRzID0gYXMubWF0cml4KGNudHMpCmFsbGNvdW50cyA9IERHRUxpc3QoY291bnRzPWNudHMpCmFsbGNvdW50cyA9IGVzdGltYXRlRGlzcChhbGxjb3VudHMsIHJvYnVzdD1UUlVFKQogIGRlc2lnbl9tYXQgPSBtb2RlbC5tYXRyaXgofiBzcnRfc2VsQHJlZHVjdGlvbnMkc3BhdGlhbEBjZWxsLmVtYmVkZGluZ3NbLDJdKQogIGZpdCA9IGdsbVFMRml0KGFsbGNvdW50cywgZGVzaWduX21hdCkKICBscnQgPSBnbG1RTEZUZXN0KGZpdCkKICB0b3AgPSB0b3BUYWdzKGxydCxuPUluZikKICB0b3AKYGBgCgoKYGBge3J9CnNydF9tYXJrZXJzID0gc3J0X3NlbEBtaXNjJG1hcmtlcnMKdG9wMTAgPC0gc3J0X21hcmtlcnNbc3J0X21hcmtlcnMkcF92YWxfYWRqPDAuMDEsXSAjJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuID0gMzAsIHd0ID0gLXBfdmFsX2FkaikgIyAlPiUgIHRvcF9uKG4gPSA1LCB3dCA9IGF2Z19sb2dGQykKdG9wMTAkcGN0X2RpZmYgPSB0b3AxMCRwY3QuMS10b3AxMCRwY3QuMgp0b3AxMCA9IHRvcDEwW3RvcDEwJHBjdF9kaWZmPjAuMSxdCnRvcDEwID0gdG9wMTAgJT4lIGdyb3VwX2J5KGdlbmUpICU+JSB0b3BfbihuPTEsd3Q9YXZnX2xvZzJGQykKCnRvcDEwID0gdG9wMTBbdG9wMTAkY2x1c3RlciAlaW4lIHNlbF9jbHVzdGVyLF0KYGBgCgpgYGB7cn0KdG9wX3NlbCA9IHRvcCR0YWJsZVtyb3duYW1lcyh0b3AkdGFibGUpICVpbiUgdG9wMTAkZ2VuZSxdCnRvcF9zZWwgPSB0b3Bfc2VsW3RvcF9zZWwkRkRSPDAuMDUsXQp3cml0ZS5jc3YodG9wX3NlbCxmaWxlID1maWxlLnBhdGgoZmlnX2RpciwgcGFzdGUwKCJERV9tYXJrZXJzZm9yY2x1c3Rlcl8iLHNlbF9jbHVzdGVyLCIuY3N2IikpKQp0b3Bfc2VsCmBgYAoKCgpgYGB7cn0Kc2VsX2dlbmUgPSBjKCJUY2Y3bDIiLCJOcjJmMiIsIldmZGMxIiwiVGFsMiIsIkJvYyIsIlppYzQiKQpGZWF0dXJlUGxvdChzcnRfc2VsLGZlYXR1cmVzID0gc2VsX2dlbmUscmVkdWN0aW9uID0gInNwYXRpYWwiLGNvb3JkLmZpeGVkID0gVCxvcmRlcj1ULHB0LnNpemU9MC41LG5jb2w9MykKZ2dzYXZlKGZpbGUucGF0aChmaWdfZGlyLHBhc3RlMCgibWFya2VyZ2VuZV8iLHNlbF9jbHVzdGVyLCJfcmVnaW9uLnBkZiIpKSkKYGBgCgpgYGB7cixmaWcud2lkdGg9OSxmaWcuaGVpZ2h0PTR9CkZlYXR1cmVQbG90KHNydDMzLGZlYXR1cmVzID0gc2VsX2dlbmUscmVkdWN0aW9uID0gInNwYXRpYWwiLGNvb3JkLmZpeGVkID0gVCxvcmRlcj1ULG5jb2w9MyxwdC5zaXplPTAuMDEpCmdnc2F2ZShmaWxlLnBhdGgoZmlnX2RpcixwYXN0ZTAoIm1hcmtlcmdlbmVfIixzZWxfY2x1c3RlciwiX2FsbHB1Y2sucGRmIikpKQpgYGAKCgpgYGB7cn0Kc2VsX2NsdXN0ZXJzID0gYygyMywgMjcpCnNydF9zZWwgPSBzcnQzM1ssc3J0MzMkc2V1cmF0X2NsdXN0ZXJzICVpbiUgc2VsX2NsdXN0ZXJzXQoKZGJfb3V0ID0gZGJzY2FuKHNydF9zZWxAcmVkdWN0aW9ucyRzcGF0aWFsQGNlbGwuZW1iZWRkaW5ncyw2MCkKCmdncGxvdChkYXRhPU5VTEwsYWVzKHg9c3J0X3NlbEByZWR1Y3Rpb25zJHNwYXRpYWxAY2VsbC5lbWJlZGRpbmdzWywxXSx5PXNydF9zZWxAcmVkdWN0aW9ucyRzcGF0aWFsQGNlbGwuZW1iZWRkaW5nc1ssMl0sY29sPSBmYWN0b3IoZGJfb3V0JGNsdXN0ZXIpKSkrCiAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjgpKwogIGNvb3JkX2ZpeGVkKCkrCiAgdGhlbWVfY2xhc3NpYygpCgpzZWxfY2x1ID0gbmFtZXModGFibGUoZGJfb3V0JGNsdXN0ZXIpW29yZGVyKHRhYmxlKGRiX291dCRjbHVzdGVyKSxkZWNyZWFzaW5nID0gVCldWzFdKQoKc3J0X3NlbCA9IHNydF9zZWxbLGRiX291dCRjbHVzdGVyPT1zZWxfY2x1XQoKCmNudHMgPSBzcnRfc2VsQGFzc2F5cyRSTkFAY291bnRzCmNudHMgPSBjbnRzW3Jvd1N1bXMoY250cyk+MjAsXQpjbnRzID0gYXMubWF0cml4KGNudHMpCmFsbGNvdW50cyA9IERHRUxpc3QoY291bnRzPWNudHMpCmFsbGNvdW50cyA9IGVzdGltYXRlRGlzcChhbGxjb3VudHMsIHJvYnVzdD1UUlVFKQogIGRlc2lnbl9tYXQgPSBtb2RlbC5tYXRyaXgofiBzcnRfc2VsQHJlZHVjdGlvbnMkc3BhdGlhbEBjZWxsLmVtYmVkZGluZ3NbLDJdKQogIGZpdCA9IGdsbVFMRml0KGFsbGNvdW50cywgZGVzaWduX21hdCkKICBscnQgPSBnbG1RTEZUZXN0KGZpdCkKICB0b3AgPSB0b3BUYWdzKGxydCxuPUluZikKCgpzcnRfbWFya2VycyA9IHNydF9zZWxAbWlzYyRtYXJrZXJzCnRvcDEwIDwtIHNydF9tYXJrZXJzW3NydF9tYXJrZXJzJHBfdmFsX2FkajwwLjAxLF0gIyU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24obiA9IDMwLCB3dCA9IC1wX3ZhbF9hZGopICMgJT4lICB0b3BfbihuID0gNSwgd3QgPSBhdmdfbG9nRkMpCnRvcDEwJHBjdF9kaWZmID0gdG9wMTAkcGN0LjEtdG9wMTAkcGN0LjIKdG9wMTAgPSB0b3AxMFt0b3AxMCRwY3RfZGlmZj4wLjIsXQojdG9wMTAgPSB0b3AxMCAlPiUgZ3JvdXBfYnkoZ2VuZSkgJT4lIHRvcF9uKG49MSx3dD1hdmdfbG9nMkZDKQoKdG9wMTAgPSB0b3AxMFt0b3AxMCRjbHVzdGVyICVpbiUgc2VsX2NsdXN0ZXJzLF0KCnRvcF9zZWwgPSB0b3AkdGFibGVbcm93bmFtZXModG9wJHRhYmxlKSAlaW4lIHRvcDEwJGdlbmUsXQp0b3Bfc2VsID0gdG9wX3NlbFt0b3Bfc2VsJEZEUjwwLjA1LF0Kd3JpdGUuY3N2KHRvcF9zZWwsZmlsZSA9ZmlsZS5wYXRoKGZpZ19kaXIsIHBhc3RlMCgiREVfbWFya2Vyc2ZvcmNsdXN0ZXJfMjNfMjcuY3N2IikpKQp0b3Bfc2VsCmBgYAoKYGBge3J9CnNlbF9nZW5lID0gYygiVGNmN2wyIiwiRG1ydGEyIiwiUnBybSIsIlR1YmIzIiwiUGNkaDgiLCJTaGgiKQpGZWF0dXJlUGxvdChzcnRfc2VsLGZlYXR1cmVzID0gc2VsX2dlbmUscmVkdWN0aW9uID0gInNwYXRpYWwiLGNvb3JkLmZpeGVkID0gVCxvcmRlcj1ULHB0LnNpemU9MC41LG5jb2w9MykKZ2dzYXZlKGZpbGUucGF0aChmaWdfZGlyLHBhc3RlMCgibWFya2VyZ2VuZV8yM18yN19yZWdpb24ucGRmIikpKQpgYGAKCmBgYHtyLGZpZy53aWR0aD05LGZpZy5oZWlnaHQ9NH0KRmVhdHVyZVBsb3Qoc3J0MzMsZmVhdHVyZXMgPSBzZWxfZ2VuZSxyZWR1Y3Rpb24gPSAic3BhdGlhbCIsY29vcmQuZml4ZWQgPSBULG9yZGVyPVQsbmNvbD0zLHB0LnNpemU9MC4wMSkKZ2dzYXZlKGZpbGUucGF0aChmaWdfZGlyLHBhc3RlMCgibWFya2VyZ2VuZV8yM18yN19hbGxwdWNrLnBkZiIpKSkKYGBgCgpgYGB7cn0KRGltUGxvdChzcnRfc2VsLHJlZHVjdGlvbiA9ICJzcGF0aWFsIikrY29vcmRfZml4ZWQoKQpgYGAKCgpgYGB7cn0Kc3J0X3NlbCRNSEIgPSAibm8iCnNydF9zZWwkTUhCW3NydF9zZWwkeWNvb3JkPjI5MDAgJiBzcnRfc2VsJHljb29yZCA8IDMxODAgJiBzcnRfc2VsJHhjb29yZD40OTAwXSA9ICJ5ZXMiCgpEaW1QbG90KHNydF9zZWwscmVkdWN0aW9uID0gInNwYXRpYWwiLGdyb3VwLmJ5ID0gIk1IQiIpK2Nvb3JkX2ZpeGVkKCkKYGBgCgoKYGBge3J9Cm1hcmtlcnMuTUhCID0gRmluZE1hcmtlcnMoc3J0X3NlbCwgZ3JvdXAuYnkgPSAiTUhCIixpZGVudC4xID0gInllcyIsaWRlbnQuMiA9ICJubyIsdmVyYm9zZSA9IEYpCm1hcmtlcnMuTUhCW21hcmtlcnMuTUhCJHBfdmFsX2FkajwwLjA1LF0KYGBgCmBgYHtyLGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTh9CnNlbF9nZW5lID0gcm93bmFtZXMobWFya2Vycy5NSEJbbWFya2Vycy5NSEIkcF92YWxfYWRqPDAuMDUsXSkKRmVhdHVyZVBsb3Qoc3J0X3NlbCxmZWF0dXJlcyA9IHNlbF9nZW5lLHJlZHVjdGlvbiA9ICJzcGF0aWFsIixjb29yZC5maXhlZCA9IFQsb3JkZXI9VCxwdC5zaXplPTAuMyxuY29sPTQpCmdnc2F2ZShmaWxlLnBhdGgoZmlnX2RpcixwYXN0ZTAoIm1hcmtlcmdlbmVfMjNfMjdfTUhCLnBkZiIpKSkKYGBgCgojIyBleWUgZ2VuZXMKCmBgYHtyfQpleWVfZ2VuZXMgPSBjKCJSYXgiLCAiVmF4MSIsICJWYXgyIiwgIlBheDIiLCAiU2l4NiIpCkZlYXR1cmVQbG90KHNydDMzLGZlYXR1cmVzID0gZXllX2dlbmVzLHJlZHVjdGlvbiA9ICJzcGF0aWFsIixjb29yZC5maXhlZCA9IFQsb3JkZXI9VCxuY29sPTMscHQuc2l6ZT0wLjAxKQpgYGAKCmBgYHtyfQpzcnQzM19leWUgPSBTY2FsZURhdGEoc3J0MzMsZmVhdHVyZXMgPSB1bmlxdWUoYyhWYXJpYWJsZUZlYXR1cmVzKHNydDMzKSwgZXllX2dlbmVzKSkgLHZlcmJvc2U9RikKYGBgCgoKCmBgYHtyfQpleHBhbmRfZ2VuZXMgPSBjKCkKZm9yKGdlIGluIGMoIlJheCIsIlZheDEiLCJTaXg2IikpewogIHByaW50KGdlKQogIGNvcnIgPSB0KGNvcigoc3J0MzNfZXllQGFzc2F5cyRSTkFAc2NhbGUuZGF0YVtnZSxdKSwgdChzcnQzM19leWVAYXNzYXlzJFJOQUBzY2FsZS5kYXRhICkpKVssMV0KICBjb3JyID0gY29yclshaXMubmEoY29ycildCiAgY29yciA9IGNvcnJbb3JkZXIoY29ycixkZWNyZWFzaW5nID0gVCldCiAgZXhwYW5kX2dlbmVzID0gYyhleHBhbmRfZ2VuZXMsIG5hbWVzKGhlYWQoY29ycikpWzI6Nl0pCn0KCmBgYAoKCgpgYGB7cn0Kc3J0MzNfZXllID0gUnVuUENBKHNydDMzX2V5ZSwgbnBjcyA9IDUsZmVhdHVyZXM9dW5pcXVlKGMoZXhwYW5kX2dlbmVzLGV5ZV9nZW5lcykpLHZlcmJvc2U9RikKc3J0MzNfZXllID0gRmluZE5laWdoYm9ycyhzcnQzM19leWUsZGltcyA9IDE6NSx2ZXJib3NlPUYpCnNydDMzX2V5ZSA9IEZpbmRDbHVzdGVycyhzcnQzM19leWUsdmVyYm9zZT1GKQpgYGAKCgpgYGB7cn0KRGltUGxvdChzcnQzM19leWUscmVkdWN0aW9uID0gInNwYXRpYWwiKQpgYGAKCgpgYGB7cn0Kc2VsX3NwYSA9IHNydDMzX2V5ZUByZWR1Y3Rpb25zJHNwYXRpYWxAY2VsbC5lbWJlZGRpbmdzW3NydDMzX2V5ZSRzZXVyYXRfY2x1c3RlcnM9PTEsXQpwbG90KHNlbF9zcGEpCmRiX291dCA9IGRic2NhbihzZWxfc3BhLGVwcz01MCkKCmdncGxvdChkYXRhPU5VTEwsYWVzKHg9c2VsX3NwYVssMV0seT1zZWxfc3BhWywyXSxjb2w9YXMuZmFjdG9yKGRiX291dCRjbHVzdGVyKSkpKwogIGdlb21fcG9pbnQoKQppZHggPSByb3duYW1lcyhzZWxfc3BhKVtkYl9vdXQkY2x1c3Rlcj09MV0Kc3J0MzNfZXllJGV5ZSA9ICJubyIKc3J0MzNfZXllJGV5ZVtjb2xuYW1lcyhzcnQzM19leWUpICVpbiUgaWR4XSA9ICJ5ZXMiCmBgYAoKYGBge3J9CnBhc3RlKHN1bShzcnQzM19leWUkZXllPT0ieWVzIiksIi8iLG5jb2woc3J0MzNfZXllWyxzcnQzM19leWUkUk5BX3Nubl9yZXMuMSAlaW4lIGMoMCwxLDE1LDIxLDIzLDI3KV0pLCI9IixzdW0oc3J0MzNfZXllJGV5ZT09InllcyIpL25jb2woc3J0MzNfZXllWyxzcnQzM19leWUkUk5BX3Nubl9yZXMuMSAlaW4lIGMoMCwxLDE1LDIxLDIzLDI3KV0pKQoKcGFzdGUoc3VtKHNydDMzX2V5ZSRleWU9PSJ5ZXMiKSwiLyIsc3VtKHNydDMzX2V5ZSRSTkFfc25uX3Jlcy4xPT0wKSwiPSIsIHN1bShzcnQzM19leWUkZXllPT0ieWVzIikvc3VtKHNydDMzX2V5ZSRSTkFfc25uX3Jlcy4xPT0wKSkKCnBhc3RlKHN1bShzcnQzM19leWUkUk5BX3Nubl9yZXMuMT09MCksIi8iLG5jb2woc3J0MzNfZXllKSwiPSIsIHN1bShzcnQzM19leWUkUk5BX3Nubl9yZXMuMT09MCkvbmNvbChzcnQzM19leWUpKQpgYGAKCgoKCmBgYHtyfQptYXJrZXIuZXllID0gRmluZE1hcmtlcnMoc3J0MzNfZXllLGdyb3VwLmJ5ID0gImV5ZSIsIGlkZW50LjEgPSAieWVzIixpZGVudC4yID0gIm5vIixtaW4uZGlmZi5wY3QgPSAwLjEsdmVyYm9zZSA9IEYpCndyaXRlLmNzdihtYXJrZXIuZXllW21hcmtlci5leWUkcF92YWxfYWRqPDAuMDEgJiBtYXJrZXIuZXllJGF2Z19sb2cyRkM+MCxdLGZpbGU9ImRhdGEvZXllc19tYXJrZXIuY3N2IikKYGBgCgoKYGBge3J9CkRpbVBsb3Qoc3J0MzNfZXllLHJlZHVjdGlvbiA9ICJzcGF0aWFsIixncm91cC5ieSA9ICJleWUiLGNvbHMgPSBjKCJncmV5ODAiLCJkb2RnZXJibHVlMiIpLHB0LnNpemU9MC4zKStjb29yZF9maXhlZCgpK3RoZW1lX3ZvaWQoKQpnZ3NhdmUoZmlsZS5wYXRoKGZpZ19kaXIscGFzdGUwKCJzcGF0aWFsX2V5ZV9yZWdpb24ucGRmIikpKQpgYGAKCmBgYHtyfQpzcnQzM19leWVfc2VsID0gc3J0MzNfZXllWyxzcnQzM19leWUkZXllPT0ieWVzIl0Kc3J0MzNfZXllX3NlbCA9IEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNydDMzX2V5ZV9zZWwsbmZlYXR1cmVzID0gMTAwMCkKc3J0MzNfZXllX3NlbCA9IFNjYWxlRGF0YShzcnQzM19leWVfc2VsLGZlYXR1cmVzID0gIHVuaXF1ZShjKFZhcmlhYmxlRmVhdHVyZXMoc3J0MzNfZXllX3NlbCksIGMoIkNwIiwiVndjMiIpKSkpCmV4cGFuZF9nZW5lc19leWUgPSBjKCkKZm9yKGdlIGluIGMoIkNwIiwiVndjMiIpKXsKICBwcmludChnZSkKICBjb3JyID0gdChjb3IoKHNydDMzX2V5ZV9zZWxAYXNzYXlzJFJOQUBzY2FsZS5kYXRhW2dlLF0pLCB0KHNydDMzX2V5ZV9zZWxAYXNzYXlzJFJOQUBzY2FsZS5kYXRhICkpKVssMV0KICBjb3JyID0gY29yclshaXMubmEoY29ycildCiAgY29yciA9IGNvcnJbb3JkZXIoY29ycixkZWNyZWFzaW5nID0gVCldCiAgZXhwYW5kX2dlbmVzX2V5ZSA9IGMoZXhwYW5kX2dlbmVzX2V5ZSwgbmFtZXMoaGVhZChjb3JyLG49MTApKVsyOjEwXSkKfQpgYGAKCgpgYGB7cn0KCnNydDMzX2V5ZV9zZWwgPSBSdW5QQ0Eoc3J0MzNfZXllX3NlbCwgbnBjcyA9IDUsZmVhdHVyZXM9dW5pcXVlKGMoZXhwYW5kX2dlbmVzX2V5ZSxjKCJDcCIsIlZ3YzIiKSkpLHZlcmJvc2U9RikKc3J0MzNfZXllX3NlbCA9IEZpbmROZWlnaGJvcnMoc3J0MzNfZXllX3NlbCxrLnBhcmFtPTEwLGRpbXMgPSAxOjUpCnNydDMzX2V5ZV9zZWwgPSBGaW5kQ2x1c3RlcnMoc3J0MzNfZXllX3NlbCkKCkRpbVBsb3Qoc3J0MzNfZXllX3NlbCxyZWR1Y3Rpb24gPSAic3BhdGlhbCIscHQuc2l6ZSA9IDQpK2Nvb3JkX2ZpeGVkKCkKZ2dzYXZlKGZpbGUucGF0aChmaWdfZGlyLCJleWVfc3Vic2V0X2NsdXN0ZXJpbmcucGRmIikpCmBgYAoKYGBge3J9CmV5ZV9zdWIubWFya2VycyA9IEZpbmRBbGxNYXJrZXJzKHNydDMzX2V5ZV9zZWwpCnRvcDEwIDwtIGV5ZV9zdWIubWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKG4gPSAxMCwgd3QgPSAtcF92YWxfYWRqKSAjICU+JSAgdG9wX24obiA9IDUsIHd0ID0gYXZnX2xvZ0ZDKQp0b3AxMCA9IHRvcDEwICU+JSBncm91cF9ieShnZW5lKSAlPiUgdG9wX24obj0xLHd0PWF2Z19sb2cyRkMpCnRvcDEwID0gdG9wMTAgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuID0gNSwgd3QgPSBhdmdfbG9nMkZDKQoKRG90UGxvdChzcnQzM19leWVfc2VsLGZlYXR1cmVzID0gdW5pcXVlKGModW5pcXVlKHRvcDEwJGdlbmUpLCJDcCIsIlZ3YzIiKSksY29scz0iU3BlY3RyYWwiKStjb29yZF9mbGlwKCkKZ2dzYXZlKGZpbGUucGF0aChmaWdfZGlyLCJleWVfc3Vic2V0X21hcmtlcnNfZG90cGxvdC5wZGYiKSkKYGBgCgoKYGBge3J9CkZlYXR1cmVQbG90KHNydDMzX2V5ZV9zZWwsZmVhdHVyZXMgPSBjKCJWd2MyIiwiSmthbXAiLCJDcCIsIlRsazEiLCJQb24yIiwiSWN0MSIpLGNvb3JkLmZpeGVkID0gVCxzb3J0LmNlbGwgPSBULHJlZHVjdGlvbiA9ICJzcGF0aWFsIixuY29sID0gMykKZ2dzYXZlKGZpbGUucGF0aChmaWdfZGlyLCJleWVfc3Vic2V0X21hcmtlcnNfc3BhdGlhbC5wZGYiKSkKYGBgCgoKCmBgYHtyLCBmaWcud2lkdGg9MTIsZmlnLmhlaWdodD04fQpwcCA9IEZlYXR1cmVQbG90KHNydDMzX2V5ZSxmZWF0dXJlcyA9IHJvd25hbWVzKG1hcmtlci5leWUpWzE6MTJdLG9yZGVyID0gVCxyYXN0ZXIgPSBGLG5jb2wgPSA0LGNvb3JkLmZpeGVkID0gVCxyZWR1Y3Rpb24gPSAic3BhdGlhbCIsbWF4LmN1dG9mZiA9ICJxOTkiKQpnZ3NhdmUoZmlsZS5wYXRoKGZpZ19kaXIscGFzdGUwKCJzcGF0aWFsX2V5ZV9tYXJrZXJzLnBkZiIpKSxwbG90ID0gcHAsd2lkdGggPSAxNCxoZWlnaHQgPSA5KQpgYGAKCgpgYGB7cn0Kc3J0MzYgPSBzcnQ5NVssc3J0OTUkb3JpZy5pZGVudD09IjIwMTEwNF8zNiJdCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMixmaWcuaGVpZ2h0PTh9CnBwID0gRmVhdHVyZVBsb3Qoc3J0MzYsZmVhdHVyZXMgPSByb3duYW1lcyhtYXJrZXIuZXllKVsxOjEyXSxvcmRlciA9IFQscmFzdGVyID0gRixuY29sID0gNCxjb29yZC5maXhlZCA9IFQscmVkdWN0aW9uID0gInNwYXRpYWwiLG1heC5jdXRvZmYgPSAicTk5IikKZ2dzYXZlKGZpbGUucGF0aChmaWdfZGlyLHBhc3RlMCgic3BhdGlhbF9leWVfbWFya2Vyc18zNi5wZGYiKSkscGxvdCA9IHBwLHdpZHRoID0gMTQsaGVpZ2h0ID0gOSkKYGBgCgpgYGB7cn0KbG9hZCgifi9zY1JOQXNlcV9yZWZlcmVuY2VfZGF0YXNldHMvV1QuUm9iaiIpCmBgYAoKCmBgYHtyfQpEaW1QbG90KFdUKQpgYGAKCgpgYGB7cn0KRmVhdHVyZVBsb3QoV1QsZmVhdHVyZXMgPSBjKCJTaXg2IiwiQ3AiLCJWd2MyIiksb3JkZXI9VCkKYGBgCgpgYGB7cixmaWcud2lkdGg9MTQsZmlnLmhlaWdodD05fQpGZWF0dXJlUGxvdChXVCxmZWF0dXJlcyA9IGMoIlNpeDYiLCJDcCIsIlZ3YzIiKSxvcmRlcj1ULHNwbGl0LmJ5ID0gInN0YWdlIikKYGBgCgpgYGB7cn0KaGlzdChXVEBhc3NheXMkUk5BQGRhdGFbIlNpeDYiLF1bV1RAYXNzYXlzJFJOQUBkYXRhWyJTaXg2IixdPjAuNV0pCmBgYAoKCmBgYHtyfQpXVCRleWVfY2x1c3RlciA9IFdUQGFzc2F5cyRSTkFAZGF0YVsiU2l4NiIsXT4wLjcKdGFibGUoV1QkZXllX2NsdXN0ZXIpCmBgYApzcGFyc2UuY29yMgoKYGBge3J9CkRpbVBsb3QoV1QsZ3JvdXAuYnk9ImV5ZV9jbHVzdGVyIixvcmRlcj1UKQpgYGAKCmBgYHtyfQp0YWJsZShXVCRleWVfY2x1c3RlcixXVCRzdGFnZSkKYGBgCgpgYGB7cn0KdGFibGUoV1QkZXllX2NsdXN0ZXIsV1QkY2x1c3RlcikKYGBgCgoKYGBge3J9CldUJGV5ZV9jbHVfZmluZSA9ICJubyIKV1QkZXllX2NsdV9maW5lWyBXVCRjbHVzdGVyPT0xMF09ImNsdTEwIgpXVCRleWVfY2x1X2ZpbmVbV1QkZXllX2NsdXN0ZXIgJiBXVCRjbHVzdGVyPT0xMF09ImV5ZV8xMCIKV1QkZXllX2NsdV9maW5lWyBXVCRjbHVzdGVyPT0yNF09ImNsdTI0IgpXVCRleWVfY2x1X2ZpbmVbV1QkZXllX2NsdXN0ZXIgJiBXVCRjbHVzdGVyPT0yNF09ImV5ZV8yNCIKdGFibGUoV1QkZXllX2NsdV9maW5lKQpgYGAKCmBgYHtyfQptYXJrZXJzXzI0ID0gRmluZE1hcmtlcnMoV1QsaWRlbnQuMSA9ICIyNCIsZ3JvdXAuYnkgPSAiY2x1c3RlciIsb25seS5wb3MgPSBULG1pbi5kaWZmLnBjdCA9IDAuMSx2ZXJib3NlID0gRikKYGBgCgoKYGBge3J9CmV5ZS4xMF9yZWYgPSBGaW5kTWFya2VycyhXVCxpZGVudC4xID0gImV5ZV8xMCIsaWRlbnQuMiA9ICJjbHUxMCIsZ3JvdXAuYnkgPSAiZXllX2NsdV9maW5lIixtaW4uZGlmZi5wY3QgPSAwLjEsdmVyYm9zZSA9IEYpCmV5ZS4xMF9yZWYgPSBleWUuMTBfcmVmW2V5ZS4xMF9yZWYkcF92YWxfYWRqPDAuMDEsXQpleWUuMTBfcmVmID0gZXllLjEwX3JlZltleWUuMTBfcmVmJHBjdC4xPjAuMyAmIGV5ZS4xMF9yZWYkcGN0LjI8MC4xLF0KZXllLjEwX3JlZgpgYGAKCmBgYHtyfQpleWUuMjRfcmVmID0gRmluZE1hcmtlcnMoV1QsaWRlbnQuMSA9ICJleWVfMjQiLGlkZW50LjIgPSAiY2x1MjQiLGdyb3VwLmJ5ID0gImV5ZV9jbHVfZmluZSIsbWluLmRpZmYucGN0ID0gMC4xLHZlcmJvc2UgPSBGKQpleWUuMjRfcmVmID0gZXllLjI0X3JlZltleWUuMjRfcmVmJHBfdmFsX2FkajwwLjAxLF0KZXllLjI0X3JlZiA9IGV5ZS4yNF9yZWZbZXllLjI0X3JlZiRwY3QuMT4wLjMgJiBleWUuMjRfcmVmJHBjdC4yPDAuMSxdCmV5ZS4yNF9yZWYKYGBgCgpgYGB7cixmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTZ9CkZlYXR1cmVQbG90KFdULGZlYXR1cmVzID0gcm93bmFtZXMoZXllLjEwX3JlZiksb3JkZXI9VCxuY29sPTMpCmBgYApgYGB7cixmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTZ9CkZlYXR1cmVQbG90KFdULGZlYXR1cmVzID0gcm93bmFtZXMoZXllLjI0X3JlZiksb3JkZXI9VCxuY29sPTMpCmBgYAoKYGBge3J9CkZlYXR1cmVQbG90KHNydDMzLGZlYXR1cmVzID0gcm93bmFtZXMoZXllLjEwX3JlZikscmVkdWN0aW9uID0gInNwYXRpYWwiLGNvb3JkLmZpeGVkID0gVCxvcmRlcj1ULG5jb2w9MyxwdC5zaXplPTAuMDEpCmBgYAoKYGBge3J9CkZlYXR1cmVQbG90KHNydDMzLGZlYXR1cmVzID0gcm93bmFtZXMoZXllLjI0X3JlZikscmVkdWN0aW9uID0gInNwYXRpYWwiLGNvb3JkLmZpeGVkID0gVCxvcmRlcj1ULG5jb2w9MyxwdC5zaXplPTAuMDEpCmBgYAoKCmBgYHtyLGZpZy53aWR0aD0xMixmaWcuaGVpZ2h0PTZ9CkZlYXR1cmVQbG90KHNydDMzLGZlYXR1cmVzID0gYygiU2l4NiIsIkFsZGgxYTMiKSxyZWR1Y3Rpb24gPSAic3BhdGlhbCIsY29vcmQuZml4ZWQgPSBULG9yZGVyPVQsYmxlbmQgPSBULHB0LnNpemU9MC4yKQpgYGAKCmBgYHtyfQpzcnQ4NSA9IHJlYWRSRFMoZmlsZSA9ICJkYXRhL3NydF9FODUuUmRzIikKYGBgCgoKYGBge3IsZmlnLndpZHRoPTQ2LGZpZy5oZWlnaHQ9MTB9CkZlYXR1cmVQbG90KHNydDg1LGZlYXR1cmVzID0gYygiU2l4NiIsIkFsZGgxYTMiLCJGb3hnMSIsIkNwIiwiVndjMiIpLHNwbGl0LmJ5ID0gIm9yaWcuaWRlbnQiLG5jb2w9NCxyZWR1Y3Rpb24gPSAic3BhdGlhbCIsY29vcmQuZml4ZWQgPSBULG9yZGVyPVQpCmdnc2F2ZShmaWxlLnBhdGgoZmlnX2RpciwiZXllX21hcmtlcnNfRTg1LnBkZiIpKQpgYGAKCgoK